using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace SerialPortCommunicationProject.Tools
{
    /// <summary>
    /// class for socket tcp server communication
    /// parent class: SocketTcpCommunication
    /// </summary>
    public class SocketTcpServerCommunication : SocketTcpCommunication
    {
        private readonly int backlog=100;
        private ObservableCollection<Socket> listeningList;
        private string localIp;
        private int localPort;


        public SocketTcpServerCommunication(int sendBufferSize, int receiveBufferSize, string localIp, int localPort) : base(sendBufferSize, receiveBufferSize)
        {
            listeningList = new ObservableCollection<Socket>();
            this.localIp = localIp;
            this.localPort = localPort;
        }

        public SocketTcpServerCommunication(string localIp, int localPort) : base() 
        {
            listeningList = new ObservableCollection<Socket>();
            this.localIp = localIp;
            this.localPort = localPort;
        }

        public ObservableCollection<Socket> ListeningList
        {
            get => listeningList;
            set
            {
                listeningList = value;
            }
        }

        public override bool Open()
        {
            if (socket == null)
            {
                return false;
            }
            IPEndPoint point = new IPEndPoint(IPAddress.Parse(localIp), localPort);
            try
            {
                socket.Bind(point);
                socket.Listen(backlog);
                IsOpen = true;
                Task.Factory.StartNew(DataReceive);
            }
            catch(Exception ex)
            {
                IsOpen = false;
                return false;
            }
            return true;
        }

        private void Receive(Socket handler)
        {
            EndPoint remotePe = handler?.RemoteEndPoint;
            int index = -1;
            if (handler != null)
            {
                index = listeningList.IndexOf(handler);
            }
            while (true)
            {
                TestConnected(handler);//heart package

                int bufferSize = 100;
                byte[] buffer = new byte[bufferSize];
                try
                {  
                    int receivedSize = handler.Receive(buffer, bufferSize, SocketFlags.None);

                    receiveBuffer = buffer.Take(receivedSize).ToArray();

                    ViewModelHelper.GenerateDataRecord(this, Status.Receive, handler.RemoteEndPoint);
                }
                catch (Exception ex)
                {
                    if (handler != null)
                    {
                        ViewModelHelper.ShowJustDisConnectedClient(remotePe);
                        if (index >= 0)
                        {
                            this.listeningList.RemoveAt(index);
                        }
                        ViewModelHelper.UpdateClientsIp(this.listeningList.Count);

                        handler?.Close();
                        handler.Dispose();
                        break;
                    }
                }
            }
        }
    
        
        public override void DataReceive()
        {
            while (true)
            {
                try
                {
                    Socket handler = socket.Accept();
                    ViewModelHelper.ShowJustConnectedClient(handler.RemoteEndPoint);
                    listeningList.Add(handler);
                    ViewModelHelper.UpdateClientsIp(this.listeningList.Count);
                    Task.Factory.StartNew(() =>
                    {
                        Receive(handler);
                    });
                }catch(Exception ex)
                {
                    return;
                }
            }
        }

        public override void Send(byte[] sendBuffer)
        {
            int index = ViewModelHelper.SelectedIPEndPointIndex - 1;
            if (index >= 0)
            {
                Socket handler = listeningList[index];
                handler.Send(sendBuffer, sendBuffer.Length, SocketFlags.None);
            }else if(index < 0)
            {
                ObservableCollection<Socket> newListeningList = new ObservableCollection<Socket>();
                //默认发all
                for(int i = 0; i < listeningList.Count; i++)
                {
                    try
                    {
                        listeningList[i].Send(sendBuffer, sendBuffer.Length, SocketFlags.None);
                        newListeningList.Add(listeningList[i]);
                    }catch(Exception ex)
                    {
                        
                    }
                    listeningList = newListeningList;
                }
            }
            this.sendBuffer = sendBuffer;
            ViewModelHelper.GenerateDataRecord(this, Status.Send);
        }
        public override bool Close()
        {
            for (int i = 0; i < listeningList.Count; i++)
            {
                listeningList[i]?.Close();
                listeningList[i]?.Dispose();
                listeningList[i] = null;
            }
            base.Close();
            return false;
        }
    }
}
